fix(intro): débloque l'intro des derniers faits (7×9/8×9/9×9) - #67
Merged
Conversation
Deux verrous empêchaient l'introduction des faits les plus durs — ceux que le seeding par dominance du placement ne peut pas inférer (au-delà du dernier fait réussi : typiquement 7×9, 8×9, 9×9). Résultat : l'image mystère restait incomplète, parfois à vie pour un enfant qui rate la table de 9 (feedback utilisateur). 1. recentlyIntroduced (filtre 48h, sessionComposer) s'appuyait sur history[0].date, qui pour un fait DOMINÉ au placement n'est pas sa date d'intro mais sa 1ʳᵉ révision. Dès que la table de 9 était revue, ses faits passaient pour « introduits récemment » et bloquaient l'intro des faits similaires. On introduit un champ explicite `introducedAt`, posé uniquement à l'écran d'intro réel (App.tsx) ; les faits dominés ne l'ont jamais → ils n'entrent plus dans la fenêtre 48h. Met le code en conformité avec specs §1.2. 2. TAIL_INTRO_THRESHOLD passait l'exception « fin de parcours » à ≤2 restants, en supposant que seuls 8×9/9×9 pouvaient rester bloqués. Le trou de dominance couvre tout le coin difficile (3+ faits). Seuil 2 → 7 (≥29/36 introduits = fin de parcours). Migration : aucune. Les profils existants n'ont pas `introducedAt` → traités comme « non introduits récemment », ce qui débloque immédiatement tout profil coincé (comportement voulu). Tests : régression dédiée (queue introduite même en ratant les ×9), gate ≤7 restants, garde-fou 48h piloté par introducedAt. Specs §3.4bis + changelog mis à jour. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
Preview supprimée (PR fermée). Les URLs ne sont plus accessibles. |
Le champ était écrit mais jamais lu : composeDivisionSession n'a pas de fenêtre 48h (§11.6), et l'anti-interférence division passe par questionConflict (même dividende). On le garde strictement là où il est lu — la multiplication. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Contexte
Feedback utilisateur (Gwennaelle) : « le même bug qu'avant sur l'image, il y a des cases non visibles ». Diagnostic : sur son profil (33/36 introduits), les 3 faits
7×9,8×9,9×9n'étaient jamais introduits → coin bas-droite de l'image mystère définitivement vide.Simulation sur son profil réel (vrai
composeSession+processAnswer) :Cause racine — deux verrous distincts
recentlyIntroducedmal déterminé (sessionComposer). Le filtre anti-interférence 48h s'appuyait surhistory[0].date. Pour un fait dominé au placement, cette date n'est pas son intro mais sa 1ʳᵉ révision : dès que la table de 9 était revue, ses faits passaient pour « introduits récemment » et bloquaient l'intro des faits partageant l'opérande 9. → champ expliciteintroducedAt, posé uniquement à l'écran d'intro réel. Les faits dominés ne l'ont jamais → exclus de la fenêtre 48h. Conforme à specs §1.2 (qui décrivait déjà ce comportement).TAIL_INTRO_THRESHOLDtrop bas (leitner). L'exception « fin de parcours » (introduire même avec des faits en boîte 1) ne se déclenchait qu'à ≤2 restants — l'auteur supposait que seuls8×9/9×9pouvaient rester bloqués. Le trou de dominance du placement couvre tout le coin difficile (3+ faits). 2 → 7 (≥29/36 introduits).Les deux sont nécessaires : (1) débloque le filtre (cas adulte/sans-faute), (2) débloque la gate (cas enfant en difficulté).
Décisions de design
recentlyIntroducedà la racine respecte l'espacement (9×9attend bien 48h après le lot7×9/8×9).introducedAt→ « non introduits récemment » → débloque immédiatement tout profil coincé. Backfill rejeté (ré-introduirait la confusion).introducedAtuniquement côté multiplication. La division n'a pas de fenêtre 48h (§11.6) — son anti-interférence passe parquestionConflict(même dividende) — donc le champ n'y a pas de raison d'être. La gateshouldIntroduceNewreste mutualisée, mais vérifiée inerte pour la division (intro garrotée par la maîtrise du parent multiplicatif ; identique au baseline sur 4 scénarios simulés).Tests
introducedAt.🤖 Generated with Claude Code